parser grammar Ccore;
import CVocab;
options {
	output = AST;
	language = Java;
	ASTLabelType = CommonTree;
}
tokens {
	FUNCDEF;
	PARA;
	TYPEDEF;
	TYPE;
	CAST;
	QUALIFY;
	VAR;
	FUNC;
	STATE;
	COMPOUND;
	LABEL;
	BRANCH;
	LOOP;
	CASE;
	JUMP;
	EXPR;
	COND;
	ASSIGN;
	CALL;
	ARG;
	VID;
	BIT;
	DELAY;
	INDEX;
	FIELD;
	REF;
	DEREF;
	NOT;
	AND;
	OR;
	XOR;
	SHL;
	SHR;
	BoolNOT;
	BoolAND;
	POSITIVE;
	NEGATIVE;
	PLUS;
	SURPLUS;
	MUL;
	DIV;
	MOD;
	LT;
	GT;
	LE;
	GE;
	EQU;
	NEQ;

}
scope SymbolTable {  //2-level scope: outside, inside function
	String name;
	Set<String> types;
}

@lexer::header {
package per.chenjw.esa.front.c;
}
@parser::header {
package per.chenjw.esa.front.c;
import java.util.Set;
import java.util.HashSet;
}
@members {
  boolean isTypeName(String name) {
    for (int s=$Scope2.size()-1; s>=0; s--) {
      if ( $Scope2[s]::types.contains(name) ) {
        //System.out.println(name+" type-defined in "+$Scope2[s]::name);
        return true;
      }
    }
    return false;
  }
}

//============================== rule section =====================================
unit scope SymbolTable; 
@init {
	$SymbolTable::name="File scope";
	$SymbolTable::types = new HashSet<String>(); // global shared variable/function declaration, typedef
}
	: declaration+
	;
declaration scope {boolean isTypedef;}
	: typedef | symboldef	;

typedef	
	:  'typedef' {$declaration::isTypedef=true;} specifiers symbol (',' symbol)* ';'    -> ^(TYPEDEF specifiers symbol)+
	;
symboldef
	:specifiers symbol (',' symbol)*                                      -> (specifiers symbol)+
	;
symbol
	:  (function | variable)	;
variable
	: declarator ('=' initializer)?                                                  -> ^(VAR  declarator initializer?)
	;
function
	: declarator parameter_list (function_body)?                       -> ^(FUNC  declarator parameter_list function_body?)
	;
function_body scope SymbolTable;
@init{
	$SymbolTable::name="Function scope";
	$SymbolTable::types=new HashSet<String>();
}	:  compound_statement
	;

specifiers
	: (storage_specifier | type_qualifier | type_specifier)*          -> ^(TYPE specifiers*)
	;
storage_specifier
	: 'static' | 'auto' | 'register' | 'extern'	;
type_qualifier
	: 'const' | 'volatile'	;
type_specifier
	: 'void'
	| ('signed' | 'unsigned')? ('short'|'long' 'long'?)? ('char'|'int'|'float'|'double')
	| ('signed' | 'unsigned')? ('short'|'long' 'long'?)
	| ('signed' | 'unsigned')
	| {isTypeName(input.LT(1).getText())}? IDENTIFIER
	;
declarator
	: '*' declarator                 -> ^(DEREF declarator)
	| qualified_declarator
	;
qualified_declarator
	: type_qualifier direct_declarator         -> (QUALIFY direct_declarator)
	| direct_declarator
	;
direct_declarator
	: (IDENTIFIER {}  -> IDENTIFIER | '(' declarator ')' -> declarator)
		( '[' expression? ']'  -> ^(INDEX $direct_declarator expression?))*
	;
parameter_list
	: '(' ')'  -> ^(PARA)
	| '(' parameter (',' parameter)* ')'       -> ^(PARA parameter)+
	;
parameter
	: specifiers symbol
	;
initializer
	: expression
	| '{'! initializer_list? '}'!
	;
initialzer_list
	: initializer (',' initializer)*','?          -> ^(INIT initializer+)
	;
expression_list
	: expression (',' expression)*                -> expression+
	;
assignment
	: (lvalue ('='|'||='|'&&='|'|='|'&='|'^='|'<<='|'>>='|'+='|'-='|'*='|'/='|'%='))=>
		lvalue ('=' assignment        -> ^(ASSIGN lvalue assignment)
			   |'||=' assignment      -> ^(ASSIGN lvalue ^(BoolOR lvalue assignment))
			   |'&&' assignment       -> ^(ASSIGN )
	
	